package transferstats

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/chihaya/chihaya/bittorrent"
	"github.com/chihaya/chihaya/middleware"
	"github.com/chihaya/chihaya/pkg/log"
	"github.com/chihaya/chihaya/pkg/stop"
)

type StatsData struct {
	UserId      int    `json:"userId"`
	InfoHash    string `json:"infoHash"`
	Uploaded    uint64 `json:"uploaded"`   // 每次announce请求的增量上传量
	Downloaded  uint64 `json:"downloaded"` // 每次announce请求的增量下载量
	PeerIp      string `json:"peerIp"`
	PeerPort    int    `json:"peerPort"`
	PeerId      string `json:"peerId"`
	LastUpdated int64  `json:"lastUpdated"`
}

type hook struct {
	config   Config
	client   *http.Client
	stats    map[string]*StatsData
	ticker   *time.Ticker
	mu       sync.RWMutex
	quitChan chan struct{}
}

type Driver interface {
	middleware.Driver
}

func (h *hook) HandleAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest, resp *bittorrent.AnnounceResponse) (context.Context, error) {

	passkey, ok := req.Params.String("passkey")
	if !ok {
		log.Info("transferstats: 没有passkey参数")
		return ctx, nil
	}

	userID, err := strconv.Atoi(passkey)
	if err != nil {

		log.Error("transferstats: invalid user ID", log.Fields{
			"error":    err.Error(),
			"passkey":  passkey,
			"infoHash": req.InfoHash.String(),
		})
		return ctx, nil
	}

	// 获取原始请求参数和HTTP头部，用于调试
	userAgent := "未知"
	if val, ok := req.Params.String("user-agent"); ok {
		userAgent = val
	}

	// 打印完整的请求参数，便于调试
	params := req.Params
	logFields := log.Fields{
		"user_id":     userID,
		"info_hash":   req.InfoHash.String(),
		"uploaded":    req.Uploaded,
		"downloaded":  req.Downloaded,
		"left":        req.Left,
		"peer_ip":     req.Peer.IP.String(),
		"peer_port":   req.Peer.Port,
		"event":       req.Event.String(),
		"peer_id":     req.Peer.ID.String(),
		"client_type": userAgent,
	}

	// 添加常见的参数
	for _, key := range []string{"uploaded", "downloaded", "left", "event", "port", "compact", "numwant"} {
		if val, ok := params.String(key); ok {
			logFields["param_"+key] = val
		}
	}

	log.Info("transferstats: 收到announce请求 [详细]", logFields)

	// 检查原始uploaded参数
	rawUploaded, hasUploaded := params.String("uploaded")
	if hasUploaded {
		log.Debug("transferstats: 客户端上报的原始上传量字符串", log.Fields{
			"user_id":      userID,
			"raw_uploaded": rawUploaded,
			"req_uploaded": req.Uploaded,
			"client_type":  userAgent,
		})
	}

	// 获取之前的记录（如果有）
	var previousUploaded, previousDownloaded uint64

	// 创建一个唯一的key，结合infoHash和passkey
	key := makeStatsKey(req.InfoHash.String(), passkey, req.Peer.ID.String())

	h.mu.RLock()
	if h.stats != nil {
		if existingStat, exists := h.stats[key]; exists {
			previousUploaded = existingStat.Uploaded
			previousDownloaded = existingStat.Downloaded
		}
	}
	h.mu.RUnlock()

	// 计算增量 - 对于做种的用户，即使当前没有上传，也发送当前总量
	var uploadedDelta, downloadedDelta uint64
	var forceUpdate bool = false

	// 如果有前值，计算增量
	if req.Uploaded > previousUploaded {
		uploadedDelta = req.Uploaded - previousUploaded
		log.Debug("transferstats: 计算上传增量", log.Fields{
			"user_id":     userID,
			"old_value":   previousUploaded,
			"new_value":   req.Uploaded,
			"delta":       uploadedDelta,
			"info_hash":   req.InfoHash.String(),
			"client_type": userAgent,
		})
		forceUpdate = true
	} else if previousUploaded > 0 && req.Uploaded < previousUploaded {
		log.Warn("transferstats: 客户端报告的上传量减少", log.Fields{
			"user_id":     userID,
			"old_value":   previousUploaded,
			"new_value":   req.Uploaded,
			"info_hash":   req.InfoHash.String(),
			"client_type": userAgent,
		})
		// 如果客户端重启，可能上报值会减少，此时使用当前值作为增量
		uploadedDelta = req.Uploaded
		forceUpdate = true
	} else if req.Event.String() == "completed" || req.Event.String() == "started" || req.Event.String() == "stopped" {
		// 对于特定事件，即使没有增量也发送当前值
		uploadedDelta = req.Uploaded
		log.Debug("transferstats: 特定事件触发上传报告", log.Fields{
			"user_id":     userID,
			"event":       req.Event.String(),
			"uploaded":    uploadedDelta,
			"info_hash":   req.InfoHash.String(),
			"client_type": userAgent,
		})
		forceUpdate = true
	} else {
		// 没有增量，但仍发送当前值（对于做种者很重要）
		uploadedDelta = req.Uploaded
		log.Debug("transferstats: 使用当前值作为上传量", log.Fields{
			"user_id":     userID,
			"uploaded":    uploadedDelta,
			"info_hash":   req.InfoHash.String(),
			"client_type": userAgent,
		})
	}

	if req.Downloaded > previousDownloaded {
		downloadedDelta = req.Downloaded - previousDownloaded
		forceUpdate = true
	} else if previousDownloaded > 0 && req.Downloaded < previousDownloaded {
		// 如果客户端重启，使用当前值
		downloadedDelta = req.Downloaded
		forceUpdate = true
	} else if req.Event.String() == "completed" || req.Event.String() == "started" || req.Event.String() == "stopped" {
		// 对于特定事件，发送当前值
		downloadedDelta = req.Downloaded
		forceUpdate = true
	} else {
		// 没有增量，但仍发送当前值
		downloadedDelta = req.Downloaded
	}

	// 创建或更新统计数据
	statsData := &StatsData{
		UserId:      userID,
		InfoHash:    req.InfoHash.String(),
		Uploaded:    uploadedDelta,
		Downloaded:  downloadedDelta,
		PeerIp:      req.Peer.IP.String(),
		PeerPort:    int(req.Peer.Port),
		PeerId:      req.Peer.ID.String(),
		LastUpdated: time.Now().Unix(),
	}

	// 更新最新值到缓存（但立即发送数据而不等待）
	h.mu.Lock()
	if h.stats == nil {
		h.stats = make(map[string]*StatsData)
	}
	// 仅保存当前状态，用于下次计算增量
	h.stats[key] = &StatsData{
		UserId:      userID,
		InfoHash:    req.InfoHash.String(),
		Uploaded:    req.Uploaded,
		Downloaded:  req.Downloaded,
		PeerIp:      req.Peer.IP.String(),
		PeerPort:    int(req.Peer.Port),
		PeerId:      req.Peer.ID.String(),
		LastUpdated: time.Now().Unix(),
	}
	h.mu.Unlock()

	// 总是发送数据，即使没有增量（对于做种者很重要）
	log.Info("transferstats: 发送用户统计数据", log.Fields{
		"user_id":      userID,
		"uploaded":     uploadedDelta,
		"downloaded":   downloadedDelta,
		"info_hash":    req.InfoHash.String(),
		"force_update": forceUpdate,
		"client_type":  userAgent,
	})

	// 总是立即发送数据
	go h.sendStatImmediately(statsData)

	return ctx, nil
}

func (h *hook) HandleScrape(ctx context.Context, req *bittorrent.ScrapeRequest, resp *bittorrent.ScrapeResponse) (context.Context, error) {

	return ctx, nil
}

// sendStatImmediately 立即发送单条统计数据，不论是否有增量
func (h *hook) sendStatImmediately(stat *StatsData) {
	if stat == nil {
		return
	}

	jsonData, err := json.Marshal(stat)
	if err != nil {
		log.Error("transferstats: failed to marshal stats", log.Fields{
			"error":     err.Error(),
			"user_id":   stat.UserId,
			"info_hash": stat.InfoHash,
		})
		return
	}

	log.Debug("transferstats: 发送JSON数据", log.Fields{
		"data":       string(jsonData),
		"uploaded":   stat.Uploaded,
		"downloaded": stat.Downloaded,
		"user_id":    stat.UserId,
	})

	// 创建请求
	req, err := http.NewRequest("POST", h.config.PTSiteEndpoint, bytes.NewBuffer(jsonData))
	if err != nil {
		log.Error("transferstats: failed to create request", log.Fields{
			"error":     err.Error(),
			"url":       h.config.PTSiteEndpoint,
			"user_id":   stat.UserId,
			"info_hash": stat.InfoHash,
		})
		return
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")

	// 使用较短超时的客户端
	client := &http.Client{
		Timeout: 2 * time.Second,
	}

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Error("transferstats: failed to send stats", log.Fields{
			"error":     err.Error(),
			"url":       h.config.PTSiteEndpoint,
			"user_id":   stat.UserId,
			"info_hash": stat.InfoHash,
		})
		return
	}

	// 读取并打印完整响应
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Error("transferstats: failed to read response", log.Fields{
			"error":   err.Error(),
			"user_id": stat.UserId,
		})
	} else {
		bodyString := string(bodyBytes)
		log.Info("transferstats: 收到响应", log.Fields{
			"status_code": resp.StatusCode,
			"body":        bodyString,
			"user_id":     stat.UserId,
			"info_hash":   stat.InfoHash,
		})
	}

	resp.Body.Close()
}


func makeStatsKey(infoHash, userID, peerID string) string {
	return fmt.Sprintf("%s:%s:%s", infoHash, userID, peerID)
}


func (h *hook) Start() {
	h.quitChan = make(chan struct{})
	// 不再使用定时器，每次请求立即发送
	log.Info("transferstats: 启动中间件，每个请求都会立即发送统计数据")
}


func (h *hook) Stop() stop.Result {

	if h.quitChan != nil {
		close(h.quitChan)
	}

	// 关闭前不再发送缓存的统计数据
	log.Info("transferstats: 正在关闭中间件")

	// 创建一个空的channel并关闭它，返回为stop.Result
	ch := make(stop.Channel)
	ch.Done()
	return ch.Result()
}
